package com.apes.fico.finance.service;

import com.apes.fico.finance.respository.IncomeStatementFormulaRepository;
import com.apes.fico.finance.respository.IncomeStatementRepository;
import com.apes.fico.masterdata.gl.model.AccountingPeriodItem;
import com.apes.fico.masterdata.gl.respository.AccountingPeriodItemRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import org.hibernate.query.NativeQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.*;

/**
 * @ClassName IncomeStatementService
 * @Description TODO
 * @Author pengyb
 * @Date 2019/3/4 17:05
 * @Version 1.0
 **/
@Service("incomeStatementService")
public class IncomeStatementService extends DomainService {
    @Autowired
    private IncomeStatementRepository incomeStatementRepository;
    @Autowired
    private IncomeStatementFormulaRepository incomeStatementFormulaRepository;
    @Autowired
    private BalanceSheetService balanceSheetService;
    @Autowired
    private AccountingPeriodItemRepository accountingPeriodItemRepository;

    @Autowired
    private EntityManager entityManager;

    public static final String CURRENT_AMOUNT = "currentAmount";       //本月数
    public static final String CURRENT_AMOUNT_YEAR = "currentAmountYear";// 本年累计数

    /**
     * 查询利润表
     *
     * @param request
     * @return
     */
    public List<Map<String, String>> findAll(SimpleRequest request) {
        String company = request.get("company");
        int month = request.get("month");
        int year = request.get("year");
        AccountingPeriodItem accountingPeriodItem = accountingPeriodItemRepository.findByCompanyAndMonthAndYear(company, month, year);
        if (accountingPeriodItem == null) throw new RuntimeException("无会计记录公司");
        int period = accountingPeriodItem.getYearMonth();


        //查询所有科目余额（有无辅助核算）
//        List<Map<String, Object>> chartAuxs;
//        List<Map<String, Object>> chartAmouts;
//        StringBuffer chart_buffer = new StringBuffer();
//        chart_buffer.append("SELECT A.DEBIT AS DEBIT,A.CREDIT AS CREDIT,A.ID AS ID,A.OPENING_BALANCE AS OPENING_BALANCE,(A.OPENING_BALANCE+(A.DEBIT-A.CREDIT))AS endingBalance," +
//                "(SELECT C.CODE  FROM MAS_ACC_OPERATING_CHART C WHERE C.ID= B.ACC_OPERATING_CHART_ID )AS CODE," +
//                "B.SUM AS TOTALAMOUNT ,(A.DEBIT-A.CREDIT-A.UN_CREDIT) AS AMOUNT FROM  ");
//        chart_buffer.append(" (SELECT T.ID, T.DEBIT,T.CREDIT,T.ACC_OPERATING_CHART_ID ,T.OPENING_BALANCE,T.UN_CREDIT,T.UN_DEBIT FROM GL_CHART T WHERE T.YEAR='" + year + "' AND T.PERIOD ='" + period + "' AND T.COMPANY_ID='" + company + "') A ");
//        chart_buffer.append(" FULL JOIN ");
//        chart_buffer.append(" (SELECT SUM(F.DEBIT+F.UN_DEBIT-F.CREDIT-F.UN_CREDIT) AS SUM ,F.ACC_OPERATING_CHART_ID AS ACC_OPERATING_CHART_ID ");
//        chart_buffer.append(" FROM ");
//        chart_buffer.append(" GL_CHART F WHERE  F.YEAR='" + year + "' AND F.PERIOD <='" + period + "'AND F.COMPANY_ID='" + company + "' GROUP BY F.ACC_OPERATING_CHART_ID) B ");
//        chart_buffer.append(" ON A.ACC_OPERATING_CHART_ID=B.ACC_OPERATING_CHART_ID");
//
//        Query query = entityManager.createNativeQuery(chart_buffer.toString());
//        query.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
//        chartAmouts = query.getResultList();
//
//        StringBuffer chart_aux_buffer = new StringBuffer();
//        chart_aux_buffer.append("SELECT A.DEBIT+A.UN_DEBIT AS DEBIT,A.CREDIT AS CREDIT,A.ID AS ID,A.OPENING_BALANCE AS OPENING_BALANCE,(A.OPENING_BALANCE+(A.DEBIT-A.CREDIT))AS endingBalance," +
//                "(SELECT C.CODE  FROM MAS_ACC_OPERATING_CHART C WHERE C.ID= B.ACC_OPERATING_CHART_ID )AS CODE," +
//                "B.SUM AS TOTALAMOUNT,(A.DEBIT+A.UN_DEBIT-A.CREDIT-A.UN_CREDIT) AS AMOUNT FROM  ");
//        chart_aux_buffer.append(" (SELECT T.ID,T.DEBIT,T.CREDIT,T.ACC_OPERATING_CHART_ID ,T.OPENING_BALANCE,T.UN_CREDIT,T.UN_DEBIT FROM GL_CHART_AUX T WHERE T.YEAR='" + year + "' AND T.PERIOD ='" + period + "'  AND T.COMPANY_ID='" + company + "') A ");
//        chart_aux_buffer.append(" FULL JOIN ");
//        chart_aux_buffer.append(" (SELECT SUM(F.DEBIT-F.CREDIT + F.UN_DEBIT - F.UN_CREDIT ) AS SUM ,F.ACC_OPERATING_CHART_ID AS ACC_OPERATING_CHART_ID ");
//        chart_aux_buffer.append(" FROM ");
//        chart_aux_buffer.append(" GL_CHART_AUX F WHERE  F.YEAR='" + year + "' AND F.PERIOD <='" + period + "'AND F.COMPANY_ID='" + company + "' GROUP BY F.ACC_OPERATING_CHART_ID) B ");
//        chart_aux_buffer.append(" ON A.ACC_OPERATING_CHART_ID=B.ACC_OPERATING_CHART_ID");
//
//        Query query2 = entityManager.createNativeQuery(chart_aux_buffer.toString());
//        query2.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
//        chartAuxs = query2.getResultList();

//        //查利润表数据
//        List<Map<String, String>> incomeStatementMaps = incomeStatementRepository.findAllByIncomeStatement();
//        List<Map<String, String>> incomeStatementFormulaMaps = incomeStatementFormulaRepository.findAllByIncomeStatementFormula();

        //查询所有科目余额（有无辅助核算）
        List<Map<String, Object>> chartAuxs;
        StringBuffer chart_buffer = new StringBuffer();
        chart_buffer.append("SELECT B.CODE,SUM(AMOUNT) AMOUNT,SUM(B.TOTALAMOUNT) TOTALAMOUNT  " +
                "    FROM (        SELECT T.ACC_OPERATING_CHART_ID, B.CODE, SUM(T.DEBIT - T.CREDIT) AS AMOUNT, 0 TOTALAMOUNT  " +
                "          FROM GL_VOUCHER A, GL_VOUCHER_ITEM T, MAS_ACC_OPERATING_CHART B  " +
                "         WHERE A.ID = T.VOUCHER_ID " +
                "           AND A.YEAR = '" + year + "' " +
                "           AND T.ACC_OPERATING_CHART_ID = B.ID  " +
                "           AND A.YEAR_MONTH = '" + period + "'  " +
                "           AND A.COMPANY_ID = '" + company + "'  " +
                "           AND NVL(A.VOUCHER_TEMPLATE_ID,'A') != '998'  " +
                "         GROUP BY T.ACC_OPERATING_CHART_ID, B.CODE  " +
                "        UNION ALL  " +
                "        SELECT T.ACC_OPERATING_CHART_ID, B.CODE, 0, SUM(T.DEBIT - T.CREDIT) AS TOTALAMOUNT  " +
                "          FROM GL_VOUCHER A, GL_VOUCHER_ITEM T, MAS_ACC_OPERATING_CHART B  " +
                "         WHERE A.ID = T.VOUCHER_ID  " +
                "           AND A.YEAR = '" + year + "' " +
                "           AND T.ACC_OPERATING_CHART_ID = B.ID  " +
                "           AND A.YEAR_MONTH <= '" + period + "'  " +
                "           AND A.COMPANY_ID = '" + company + "'  " +
                "           AND NVL(A.VOUCHER_TEMPLATE_ID,'A') != '998'  " +
                "         GROUP BY T.ACC_OPERATING_CHART_ID, B.CODE  ) B  " +
                "      GROUP BY B.CODE");
        Query query = entityManager.createNativeQuery(chart_buffer.toString());
        query.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
        chartAuxs = query.getResultList();

        //新版
        List<Map<String, String>> incomeStatementMaps = new ArrayList<>();
        List<Map> incomes = incomeStatementFormulaRepository.findIncome();

        for (int i = 0; i < incomes.size(); i++) {
            Map income = incomes.get(i);
            Map map = new HashMap();
            map.put("project", income.get("PROJECT"));
            map.put("id", income.get("ID"));
            map.put("currentYearEquation", income.get("CURRENT_YEAR_EQUATION"));
            map.put("instantEquation", income.get("INSTANT_EQUATION"));
            if (Objects.nonNull(income.get("ASSCHART"))){
                map.put("currentAmount", income.get("ASSCHART"));
                map.put("currentAmountYear", income.get("ASSCHART"));
            }
            incomeStatementMaps.add(map);
        };

        //拼接利润表数据
//        incomeStatementMaps = fun(incomeStatementMaps, incomeStatementFormulaMaps);

        //将余额信息由list集合中写入Map中，key存放科目代码(绝对唯一)，取值根据科目代码
        Map<String, Map<String, Object>> curMap = new HashMap<>(chartAuxs.size());
//        for (Map<String, Object> map : chartAmouts) {
//            curMap.put(map.get("CODE").toString(), map);
//        }
        for (Map<String, Object> map : chartAuxs) {
            curMap.put(map.get("CODE").toString(), map);
        }
        //求值
        Map<String, Map> mapMap = new HashMap<>();
        for (int i = 0; i < incomeStatementMaps.size(); i++) {
            Map map = new HashMap();
            map.put(CURRENT_AMOUNT, 0);
            map.put(CURRENT_AMOUNT_YEAR, 0);
            if (incomeStatementMaps.get(i).containsKey("currentAmount")) {
                Map<String, Double> doubleMap = split(incomeStatementMaps.get(i).get("currentAmount"), curMap);
                incomeStatementMaps.get(i).put(CURRENT_AMOUNT, String.valueOf(doubleMap.get("amount")));
                incomeStatementMaps.get(i).put(CURRENT_AMOUNT_YEAR, String.valueOf(doubleMap.get("totalAmount")));

                //将数据再放入map中，方便后续运算
                map.put(CURRENT_AMOUNT, incomeStatementMaps.get(i).get(CURRENT_AMOUNT));
                map.put(CURRENT_AMOUNT_YEAR, incomeStatementMaps.get(i).get(CURRENT_AMOUNT_YEAR));

            }
            mapMap.put(incomeStatementMaps.get(i).get("id"), map);
        }
        for (int i = 0; i < incomeStatementMaps.size(); i++) {
            Map map = mapMap.get(incomeStatementMaps.get(i).get("id"));
            Double dValue_B = 0.0;
            Double dValue_C = 0.0;
            if (incomeStatementMaps.get(i).get("instantEquation") != null) {
                dValue_B = equation(incomeStatementMaps.get(i).get("instantEquation"), CURRENT_AMOUNT, mapMap).get(CURRENT_AMOUNT);
                incomeStatementMaps.get(i).put(CURRENT_AMOUNT, dValue_B.toString());
                map.put(CURRENT_AMOUNT, dValue_B);
            }
            if (incomeStatementMaps.get(i).get("currentYearEquation") != null) {
                dValue_C = equation(incomeStatementMaps.get(i).get("currentYearEquation"), CURRENT_AMOUNT_YEAR, mapMap).get(CURRENT_AMOUNT_YEAR);
                incomeStatementMaps.get(i).put(CURRENT_AMOUNT_YEAR, dValue_C.toString());
                map.put(CURRENT_AMOUNT_YEAR, dValue_C);
            }
            mapMap.put(incomeStatementMaps.get(i).get("id"), map);
        }
        return incomeStatementMaps;
    }

    /**
     * 公式计算
     *
     * @param str
     * @param equation
     * @return
     */
    private Map<String, Double> equation(String str, String equation, Map<String, Map> mapMap) {
        Map arrayMap = balanceSheetService.equationSplit(str);
        String[] strs1 = (String[]) arrayMap.get("strs1");//去符号数组
        String[] strs2 = (String[]) arrayMap.get("strs2");//去数字数组
        double amount = 0;
        for (int i = 0; i < strs1.length; i++) {
            String seq = strs1[i];
            Map map = mapMap.get(seq);
            double data = 0;
            if (map.containsKey(equation)) {
                data = Double.parseDouble(String.valueOf(map.get(equation)));
            }

            if (i == 0) {
                amount += data;
            } else {
                if (strs2[i - 1].equals("+")) {
                    amount += data;
                } else {
                    amount = amount - data;
                }
            }
        }
        Map map = new HashMap();
        map.put(equation, amount);
        return map;
    }

    /**
     * 解析表达式
     *
     * @param incomeStatementMaps
     * @param incomeStatementFormulaMaps
     * @return
     */
    private List<Map<String, String>> fun(List<Map<String, String>> incomeStatementMaps, List<Map<String, String>> incomeStatementFormulaMaps) {
        Map<String, Map> mapMap = new HashMap<>();
        for (Map<String, String> map : incomeStatementFormulaMaps) {
            if (mapMap.containsKey("incomeStatement_id")) {
                map.put("code", mapMap.get("incomeStatement_id").get("code") + "$" + map.get("orientation") + "$" + map.get("code"));
            } else {
                map.put("code", map.get("orientation") + "$" + map.get("code"));
            }
            mapMap.put(map.get("incomeStatement_id"), map);
        }
        for (int i = 0; i < incomeStatementMaps.size(); i++) {
            if (mapMap.containsKey(incomeStatementMaps.get(i).get("id"))) { //相等即存在表达式
                incomeStatementMaps.get(i).put(CURRENT_AMOUNT, mapMap.get(incomeStatementMaps.get(i).get("id")).get("code").toString());
                incomeStatementMaps.get(i).put(CURRENT_AMOUNT_YEAR, mapMap.get(incomeStatementMaps.get(i).get("id")).get("code").toString());
            }
        }
        return incomeStatementMaps;
    }

    /**
     * 字符分割后求值(每期发生额)
     *
     * @param str
     * @param map
     * @return
     */
    private Map<String, Double> split(String str, Map<String, Map<String, Object>> map) {
        Map<String, Map<String, String>> chartMap = new HashMap<>();
        String regex = "\\$";
        String[] strs = str.split(regex);
        double amount = 0;
        double totalAmount = 0;

        for (int i = 0; i < strs.length; i++) {
            String codeStr = strs[i];
            String[] codeStrs = codeStr.split("#");
            String code = codeStrs[1];
            String orientation = codeStrs[0]; //运算符

            chartMap = getLikeByMap(map, code);

            if (chartMap.size() != 0) {
                Map<String, Double> byMap = getValueByMap(chartMap);
                if (orientation.equals("-")) {
                    //每期发生额+累计发生额
                    amount += byMap.get("amount") * -1.0;
                    totalAmount += byMap.get("totalAmount") * -1.0;
                } else {
                    //每期发生额+累计发生额
                    amount += byMap.get("amount");
                    totalAmount += byMap.get("totalAmount");
                }

            }

        }
        Map<String, Double> doubleMap = new HashMap<>();
        doubleMap.put("amount", amount);
        doubleMap.put("totalAmount", totalAmount);
        return doubleMap;
    }

    /**
     * 自定义Map的value求值
     *
     * @param map
     * @return
     */
    public static Map<String, Double> getValueByMap(Map<String, Map<String, String>> map) {
        double amount = 0;
        double totalAmount = 0;
        double endingBalance = 0;
        for (Map.Entry<String, Map<String, String>> entry : map.entrySet()) {
            if (entry.getValue().containsKey("AMOUNT")) {
                amount += Double.parseDouble(String.valueOf(entry.getValue().get("AMOUNT") == null ? "0" : entry.getValue().get("AMOUNT")));
            }
            if (entry.getValue().containsKey("TOTALAMOUNT")) {
                totalAmount += Double.parseDouble(String.valueOf(entry.getValue().get("TOTALAMOUNT") == null ? "0" : entry.getValue().get("TOTALAMOUNT")));
            }
            if (entry.getValue().containsKey("endingBalance")) {
                endingBalance += Double.parseDouble(String.valueOf(entry.getValue().get("endingBalance") == null ? "0" : entry.getValue().get("endingBalance")));
            }
        }
        Map<String, Double> maps = new HashMap<>();
        maps.put("amount", amount);
        maps.put("totalAmount", totalAmount);
        maps.put("endingBalance", endingBalance);

        return maps;
    }

    /**
     * 自定义Map集合key头部模糊匹配
     *
     * @param map
     * @param keyLike
     * @return
     */
    public static Map getLikeByMap(Map<String, Map<String, Object>> map, String keyLike) {
        Map<String, Map> chartMap = new HashMap<>();
        for (Map.Entry<String, Map<String, Object>> entity : map.entrySet()) {
            if (entity.getKey().substring(0, keyLike.length()).equals(keyLike)) {
                chartMap.put(entity.getKey(), entity.getValue());
            }
        }
        return chartMap;
    }
}
